//! 文本格式化器模块
//!
//! 提供默认的文本格式化器实现。

use time::format_description::FormatItem;
use time::macros::format_description;

use crate::event::LogEvent;
use crate::formatter::Formatter;

/// 时间格式描述：YYYY-MM-DD HH:MM:SS.mmm
const TIME_FORMAT: &[FormatItem<'static>] =
    format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond digits:3]");

/// 时间格式化失败时的占位符
const TIME_FALLBACK: &str = "????-??-?? ??:??:??.???";

/// 默认文本格式化器
///
/// 输出格式：`{time} [{level}] {target}: {message}`
///
/// - 时间格式：`YYYY-MM-DD HH:MM:SS.mmm`（毫秒精度）
/// - 级别：大写，固定宽度 5 字符（如 "INFO "、"FATAL"）
///
/// # 示例
///
/// ```rust
/// use log4r::formatter::{Formatter, TextFormatter};
/// use log4r::{Level, LogEvent};
///
/// let formatter = TextFormatter::new();
/// let event = LogEvent::new(Level::Info, "my_app::module", "服务启动成功");
/// let output = formatter.format(&event);
/// // 输出类似：2025-12-01 10:30:45.123 [INFO ] my_app::module: 服务启动成功
/// println!("{}", output);
/// ```
///
/// # 输出示例
///
/// ```text
/// 2025-12-01 10:30:45.123 [TRACE] my_app::module: 详细跟踪信息
/// 2025-12-01 10:30:45.124 [DEBUG] my_app::module: 调试信息
/// 2025-12-01 10:30:45.125 [INFO ] my_app::module: 服务启动成功
/// 2025-12-01 10:30:45.126 [WARN ] my_app::module: 警告信息
/// 2025-12-01 10:30:45.127 [ERROR] my_app::module: 错误信息
/// 2025-12-01 10:30:45.128 [FATAL] my_app::module: 致命错误
/// ```
#[derive(Debug, Clone, Default)]
pub struct TextFormatter;

// 编译时断言：验证 TextFormatter 实现 Send + Sync
const _: () = {
    const fn assert_send_sync<T: Send + Sync>() {}
    assert_send_sync::<TextFormatter>();
};

impl TextFormatter {
    /// 创建新的文本格式化器
    ///
    /// # 示例
    ///
    /// ```rust
    /// use log4r::formatter::TextFormatter;
    ///
    /// let formatter = TextFormatter::new();
    /// ```
    #[inline]
    pub fn new() -> Self {
        Self
    }

    /// 格式化时间戳
    ///
    /// 优先使用原始时间戳格式化，失败时降级到 UTC，最后降级到占位符。
    #[inline]
    fn format_timestamp(&self, event: &LogEvent) -> String {
        // 优先使用原始时间戳格式化
        event.timestamp.format(TIME_FORMAT).unwrap_or_else(|_| {
            // 降级：尝试使用 UTC 时间
            event
                .timestamp
                .to_offset(time::UtcOffset::UTC)
                .format(TIME_FORMAT)
                .unwrap_or_else(|_| TIME_FALLBACK.to_string())
        })
    }

    /// 格式化级别为固定宽度 5 字符
    ///
    /// 使用左对齐，不足 5 字符用空格填充。
    #[inline]
    fn format_level(&self, event: &LogEvent) -> String {
        format!("{:<5}", event.level.as_str())
    }
}

impl Formatter for TextFormatter {
    /// 将日志事件格式化为文本字符串
    ///
    /// 输出格式：`{time} [{level}] {target}: {message}`
    ///
    /// # Arguments
    ///
    /// * `event` - 要格式化的日志事件
    ///
    /// # Returns
    ///
    /// 格式化后的字符串
    ///
    /// # 示例
    ///
    /// ```rust
    /// use log4r::formatter::{Formatter, TextFormatter};
    /// use log4r::{Level, LogEvent};
    ///
    /// let formatter = TextFormatter::new();
    /// let event = LogEvent::new(Level::Warn, "my_app", "警告信息");
    /// let output = formatter.format(&event);
    /// assert!(output.contains("[WARN ]"));
    /// ```
    fn format(&self, event: &LogEvent) -> String {
        let timestamp = self.format_timestamp(event);
        let level = self.format_level(event);

        format!(
            "{} [{}] {}: {}",
            timestamp, level, event.target, event.message
        )
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;
    use crate::Level;

    // UT-2.5-001: 测试 TextFormatter 实现 Formatter trait
    #[test]
    fn test_text_formatter_implements_formatter_trait() {
        // GIVEN: TextFormatter 实例
        let formatter: Box<dyn Formatter> = Box::new(TextFormatter::new());
        let event = LogEvent::new(Level::Info, "test", "message");

        // WHEN: 调用 format 方法
        let output = formatter.format(&event);

        // THEN: 应返回格式化字符串
        assert!(!output.is_empty());
    }

    // UT-2.5-002: 测试输出格式正确
    #[test]
    fn test_text_formatter_output_format() {
        // GIVEN: TextFormatter 和 LogEvent
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "my_app::module", "Hello");

        // WHEN: 格式化事件
        let output = formatter.format(&event);

        // THEN: 输出应包含正确的格式元素
        assert!(output.contains("[INFO ]"), "应包含级别: {}", output);
        assert!(
            output.contains("my_app::module:"),
            "应包含 target: {}",
            output
        );
        assert!(output.contains("Hello"), "应包含消息: {}", output);
    }

    // UT-2.5-003: 测试时间格式正确（毫秒精度）
    #[test]
    fn test_text_formatter_time_format() {
        // GIVEN: TextFormatter 和 LogEvent
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", "message");

        // WHEN: 格式化事件
        let output = formatter.format(&event);

        // THEN: 时间格式应为 YYYY-MM-DD HH:MM:SS.mmm
        // 验证格式：前 23 个字符应匹配时间格式
        let time_part = &output[..23];
        assert!(time_part.len() == 23, "时间部分应为 23 字符: {}", time_part);
        // 验证分隔符位置
        assert_eq!(&time_part[4..5], "-", "年月分隔符");
        assert_eq!(&time_part[7..8], "-", "月日分隔符");
        assert_eq!(&time_part[10..11], " ", "日期时间分隔符");
        assert_eq!(&time_part[13..14], ":", "时分分隔符");
        assert_eq!(&time_part[16..17], ":", "分秒分隔符");
        assert_eq!(&time_part[19..20], ".", "秒毫秒分隔符");
    }

    // UT-2.5-004: 测试级别固定宽度 5 字符
    #[test]
    fn test_text_formatter_level_width() {
        // GIVEN: TextFormatter
        let formatter = TextFormatter::new();

        // WHEN/THEN: 所有级别应格式化为 5 字符宽度
        for level in [
            Level::Trace,
            Level::Debug,
            Level::Info,
            Level::Warn,
            Level::Error,
            Level::Fatal,
        ] {
            let event = LogEvent::new(level, "test", "message");
            let output = formatter.format(&event);

            // 提取 [XXXXX] 部分
            let level_start = output.find('[').unwrap_or(0);
            let level_end = output.find(']').unwrap_or(0);
            let level_str = &output[level_start + 1..level_end];

            assert_eq!(
                level_str.len(),
                5,
                "级别 '{}' 应为 5 字符，实际: '{}'",
                level,
                level_str
            );
        }
    }

    // UT-2.5-005: 编译时验证 Send + Sync
    #[test]
    fn test_text_formatter_send_sync() {
        // GIVEN/WHEN: 编译时断言函数
        fn assert_send_sync<T: Send + Sync>() {}

        // THEN: TextFormatter 应实现 Send + Sync（编译通过即验证成功）
        assert_send_sync::<TextFormatter>();
    }

    // UT-2.5-006: 测试各级别格式化输出
    #[test]
    fn test_all_levels_format_correctly() {
        // GIVEN: TextFormatter
        let formatter = TextFormatter::new();

        // WHEN/THEN: 所有级别应正确格式化
        let test_cases = [
            (Level::Trace, "[TRACE]"),
            (Level::Debug, "[DEBUG]"),
            (Level::Info, "[INFO ]"),
            (Level::Warn, "[WARN ]"),
            (Level::Error, "[ERROR]"),
            (Level::Fatal, "[FATAL]"),
        ];

        for (level, expected_level_str) in test_cases {
            let event = LogEvent::new(level, "app", "msg");
            let output = formatter.format(&event);
            assert!(
                output.contains(expected_level_str),
                "级别 {:?} 应包含 '{}', 实际输出: {}",
                level,
                expected_level_str,
                output
            );
        }
    }

    // UT-2.5-007: 测试 Default trait
    #[test]
    fn test_text_formatter_default() {
        // GIVEN: 验证 TextFormatter 实现 Default trait
        fn assert_default<T: Default>() {}
        assert_default::<TextFormatter>();

        // WHEN: 使用 new() 创建（等效于 default()）
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", "message");

        // THEN: 应正常工作
        let output = formatter.format(&event);
        assert!(output.contains("[INFO ]"));
    }

    // UT-2.5-008: 测试 Clone trait
    #[test]
    fn test_text_formatter_clone() {
        // GIVEN: TextFormatter 实例
        let formatter = TextFormatter::new();

        // WHEN: 克隆
        let cloned = formatter.clone();
        let event = LogEvent::new(Level::Info, "test", "message");

        // THEN: 克隆应正常工作
        let output1 = formatter.format(&event);
        let output2 = cloned.format(&event);
        assert_eq!(output1, output2);
    }

    // UT-2.5-009: 测试时间格式化降级路径 - 使用无效时间戳
    #[test]
    fn test_timestamp_fallback_to_utc() {
        use time::{Date, Month, PrimitiveDateTime, Time, UtcOffset};

        // GIVEN: 创建一个带有极端时区偏移的时间戳
        let date = Date::from_calendar_date(2025, Month::January, 1).unwrap();
        let time = Time::from_hms(12, 0, 0).unwrap();
        let datetime = PrimitiveDateTime::new(date, time);
        // 使用一个有效的 UTC 偏移
        let timestamp = datetime.assume_offset(UtcOffset::UTC);

        let event = LogEvent {
            timestamp,
            level: Level::Info,
            target: std::borrow::Cow::Borrowed("test"),
            message: std::borrow::Cow::Borrowed("message"),
            write_to_syslog: false,
        };

        // WHEN: 格式化事件
        let formatter = TextFormatter::new();
        let output = formatter.format(&event);

        // THEN: 应成功格式化（不会 panic）
        assert!(output.contains("2025-01-01"));
        assert!(output.contains("12:00:00"));
    }

    // UT-2.5-010: 测试 format_level 方法直接调用
    #[test]
    fn test_format_level_direct() {
        // GIVEN: TextFormatter 和各级别事件
        let formatter = TextFormatter::new();

        // WHEN/THEN: 验证 format_level 返回正确宽度
        for level in [
            Level::Trace,
            Level::Debug,
            Level::Info,
            Level::Warn,
            Level::Error,
            Level::Fatal,
        ] {
            let event = LogEvent::new(level, "test", "msg");
            let level_str = formatter.format_level(&event);
            assert_eq!(level_str.len(), 5, "级别 {:?} 格式化后应为 5 字符", level);
        }
    }

    // UT-2.5-011: 测试 format_timestamp 方法直接调用
    #[test]
    fn test_format_timestamp_direct() {
        // GIVEN: TextFormatter 和事件
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", "message");

        // WHEN: 直接调用 format_timestamp
        let timestamp_str = formatter.format_timestamp(&event);

        // THEN: 应返回正确格式的时间字符串
        assert_eq!(timestamp_str.len(), 23, "时间戳应为 23 字符");
        assert!(timestamp_str.contains("-"), "应包含日期分隔符");
        assert!(timestamp_str.contains(":"), "应包含时间分隔符");
        assert!(timestamp_str.contains("."), "应包含毫秒分隔符");
    }

    // UT-2.5-012: 测试 format 方法完整输出格式
    #[test]
    fn test_format_complete_output() {
        // GIVEN: TextFormatter 和事件
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Error, "my_app::db", "连接失败");

        // WHEN: 格式化
        let output = formatter.format(&event);

        // THEN: 输出格式应为 "{time} [{level}] {target}: {message}"
        // 验证各部分存在且顺序正确
        let time_end = output.find(" [").expect("应有时间和级别分隔");
        let level_start = time_end + 2;
        let level_end = output.find("] ").expect("应有级别结束括号");
        let target_start = level_end + 2;
        let target_end = output.find(": ").expect("应有 target 和消息分隔");

        // 验证时间部分（23 字符）
        assert_eq!(time_end, 23, "时间部分应为 23 字符");

        // 验证级别部分（5 字符）
        let level_str = &output[level_start..level_end];
        assert_eq!(level_str.len(), 5, "级别应为 5 字符");
        assert_eq!(level_str, "ERROR");

        // 验证 target
        let target_str = &output[target_start..target_end];
        assert_eq!(target_str, "my_app::db");

        // 验证消息
        assert!(output.ends_with("连接失败"));
    }

    // UT-2.5-013: 测试空消息格式化
    #[test]
    fn test_format_empty_message() {
        // GIVEN: 空消息事件
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", "");

        // WHEN: 格式化
        let output = formatter.format(&event);

        // THEN: 应正常格式化，消息部分为空
        assert!(output.contains("[INFO ]"));
        assert!(output.contains("test:"));
        assert!(output.ends_with(": "));
    }

    // UT-2.5-014: 测试空 target 格式化
    #[test]
    fn test_format_empty_target() {
        // GIVEN: 空 target 事件
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "", "message");

        // WHEN: 格式化
        let output = formatter.format(&event);

        // THEN: 应正常格式化
        assert!(output.contains("[INFO ]"));
        assert!(output.contains(": message"));
    }

    // UT-2.5-015: 测试长消息格式化
    #[test]
    fn test_format_long_message() {
        // GIVEN: 超长消息
        let long_msg = "A".repeat(10000);
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", long_msg.clone());

        // WHEN: 格式化
        let output = formatter.format(&event);

        // THEN: 消息应完整保留
        assert!(output.contains(&long_msg));
        assert!(output.len() > 10000);
    }

    // UT-2.5-016: 测试 Unicode 消息格式化
    #[test]
    fn test_format_unicode_message() {
        // GIVEN: Unicode 消息
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "日志::模块", "消息 🚀 émoji");

        // WHEN: 格式化
        let output = formatter.format(&event);

        // THEN: Unicode 应正确显示
        assert!(output.contains("日志::模块"));
        assert!(output.contains("消息 🚀 émoji"));
    }

    // UT-2.5-017: 测试特殊字符消息格式化
    #[test]
    fn test_format_special_characters() {
        // GIVEN: 包含特殊字符的消息
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", "line1\nline2\ttab");

        // WHEN: 格式化
        let output = formatter.format(&event);

        // THEN: 特殊字符应保留
        assert!(output.contains("line1\nline2\ttab"));
    }

    // UT-2.5-018: 测试 TextFormatter 作为 trait object
    #[test]
    fn test_text_formatter_as_trait_object() {
        // GIVEN: TextFormatter 作为 Box<dyn Formatter>
        let formatter: Box<dyn Formatter> = Box::new(TextFormatter::new());
        let event = LogEvent::new(Level::Warn, "trait_test", "warning");

        // WHEN: 通过 trait object 调用
        let output = formatter.format(&event);

        // THEN: 应正常工作
        assert!(output.contains("[WARN ]"));
        assert!(output.contains("trait_test"));
        assert!(output.contains("warning"));
    }

    // UT-2.5-019: 测试多次格式化同一事件
    #[test]
    fn test_format_same_event_multiple_times() {
        // GIVEN: TextFormatter 和事件
        let formatter = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", "message");

        // WHEN: 多次格式化
        let output1 = formatter.format(&event);
        let output2 = formatter.format(&event);
        let output3 = formatter.format(&event);

        // THEN: 结果应一致
        assert_eq!(output1, output2);
        assert_eq!(output2, output3);
    }

    // UT-2.5-020: 测试不同 formatter 实例格式化相同事件
    #[test]
    fn test_different_formatters_same_event() {
        // GIVEN: 两个 TextFormatter 实例
        let formatter1 = TextFormatter::new();
        let formatter2 = TextFormatter::new();
        let event = LogEvent::new(Level::Info, "test", "message");

        // WHEN: 分别格式化
        let output1 = formatter1.format(&event);
        let output2 = formatter2.format(&event);

        // THEN: 结果应一致
        assert_eq!(output1, output2);
    }

    // UT-2.5-021: 测试 UTC 时间戳格式化
    #[test]
    fn test_format_utc_timestamp() {
        use time::{Date, Month, PrimitiveDateTime, Time, UtcOffset};

        // GIVEN: 使用 UTC 时间戳的事件
        let date = Date::from_calendar_date(2025, Month::March, 15).unwrap();
        let time = Time::from_hms_milli(14, 30, 45, 123).unwrap();
        let datetime = PrimitiveDateTime::new(date, time);
        let timestamp = datetime.assume_offset(UtcOffset::UTC);

        let event = LogEvent {
            timestamp,
            level: Level::Info,
            target: std::borrow::Cow::Borrowed("utc_test"),
            message: std::borrow::Cow::Borrowed("utc message"),
            write_to_syslog: false,
        };

        // WHEN: 格式化
        let formatter = TextFormatter::new();
        let output = formatter.format(&event);

        // THEN: 时间应正确格式化
        assert!(output.contains("2025-03-15"));
        assert!(output.contains("14:30:45.123"));
    }

    // UT-2.5-022: 测试带时区偏移的时间戳格式化
    #[test]
    fn test_format_offset_timestamp() {
        use time::{Date, Month, PrimitiveDateTime, Time, UtcOffset};

        // GIVEN: 使用 +08:00 时区的事件
        let date = Date::from_calendar_date(2025, Month::July, 20).unwrap();
        let time = Time::from_hms_milli(9, 15, 30, 500).unwrap();
        let datetime = PrimitiveDateTime::new(date, time);
        let offset = UtcOffset::from_hms(8, 0, 0).unwrap();
        let timestamp = datetime.assume_offset(offset);

        let event = LogEvent {
            timestamp,
            level: Level::Debug,
            target: std::borrow::Cow::Borrowed("offset_test"),
            message: std::borrow::Cow::Borrowed("offset message"),
            write_to_syslog: false,
        };

        // WHEN: 格式化
        let formatter = TextFormatter::new();
        let output = formatter.format(&event);

        // THEN: 时间应正确格式化
        assert!(output.contains("2025-07-20"));
        assert!(output.contains("09:15:30.500"));
    }
}
